﻿using System.Collections.Generic;
using System.Linq;
using Sustainalytics.Reporting.Framework;
using Foxit.PDF.PageElements;
using Foxit.PDF;
using Sustainalytics.RiskRatings.Reporting.Charts;
using Sustainalytics.Entities.RiskRatings;
using Foxit.PDF.Imaging;
using System;
using System.Text;
using Sustainalytics.Entities;
using Sustainalytics.Utils;

namespace Sustainalytics.RiskRatings.Reporting
{
    public class CoreAppendixSection : PdfReportSectionGenerator
    {
        public CoreAppendixSection(int index):base(index)
        {
            this._reportSection.Name = "Core Appendix section";
        }

        float ColumnWidth;
        float XRightColumn;
        private static readonly IndicatorCodeComparer _indicatorComparer = new IndicatorCodeComparer();

        private float Event_CurrentXOffset { get; set; }
        private float Event_LeftYOffset { get; set; }
        private float Event_CurrentYOffset { get; set; }
        private PdfReportPage CurrentPage { get; set; }
        private RiskRatingMaterialEsgIssueBase CurrentIssue { get; set; }

        public override void ComposeSectionContent()
        {
            isCoreReport = _dataSource.ReportType == ReportType.CoreRiskRatingsReport || _dataSource.ReportType == ReportType.SummaryCoreRiskRatingsReport;
            if (_dataSource.CoreCompanyProfile.Indicators.Any())
            {
                ColumnWidth = (_report.PageMaxWidth - (float)HorisontalSpacing.Large) / 2;
                
                XRightColumn = ColumnWidth + (float)HorisontalSpacing.Large;
                var sortedList = _dataSource.CoreCompanyProfile.Indicators.OrderBy(y => y.Code, _indicatorComparer).ToList();
                var page = new PdfReportPage_Core(_report, _dataSource,3);
                OutlinePosition parentOutlinePositions = new OutlinePosition { Name = "Appendix", PageNumber = OutlinePageCount, VerticalPosition = page.Top - HeaderHeight };
                parentOutlinePositions.ChildOutlinePositions = new List<OutlinePosition>();
                OutlinePositions.Add(parentOutlinePositions);
                _report.Pages.Add(page);
                OutlinePageCount = 0;

                float currentYOffset = page.Top + 13f;
                var management_details_image = ReportHelper.GetFile("icon-management.png");
                page.Elements.Add(new Image(ImageData.GetImage(management_details_image), 0f, currentYOffset-2, 0.3f));
                currentYOffset += 5;
                page.Elements.Add(new Label("Management Details", 35f, currentYOffset, 135f, 12f, Fonts.MontserratBold, 10f, TextAlign.Left, RgbColor.Black));
                currentYOffset += 5;
                page.Elements.Add(new Line(150f, currentYOffset, _report.PageMaxWidth, currentYOffset, 1, RgbColor.Black));
                currentYOffset += 30;

                AddIndicators(sortedList, page, 0, currentYOffset, parentOutlinePositions);
                AddMaterialIssues_EventsPage(sortedList, 0, currentYOffset, _report.PageMaxWidth, null);
                OutlinePageCount++;
            }
        }

        #region Indicator section

        private void AddIndicators(List<CoreRiskRatingIndicator> indicators, PdfReportPage page, float x, float top, OutlinePosition parentOutlinePositions)
        {
            var maxWidth = 255f;
            page.Elements.Add(new Label("Indicators Details".ToUpper(), x, top, maxWidth, (float)TextSizes.SubSectionTitle, 
                Fonts.MontserratRegular, (float)TextSizes.SubSectionTitle, TextAlign.Left, RgbColor.Black));
            top += 20;

            var standardIndicators = indicators
                .Where(i => i.IndicatorType == IndicatorType.StandardIndicator)
                .ToList();

            if (!standardIndicators.Any()) return;

            var maxHeight = _report.PageMaxHeight - top;

            PdfReportPage nextPage = null;
            Table firstTable = null;
            Table secondTable = null;
            bool isNewPage = false;

            for (var skip = 1; skip <= standardIndicators.Count; skip += 2)
            {
                if (nextPage == null && skip > 2 && top > 600f)
                {
                    page = new PdfReportPage_Core(_report, _dataSource, 3);
                    _report.Pages.Add(page);
                    OutlinePageCount++;

                    float currentYOffset = page.Top + 13f;
                    var management_details_image = ReportHelper.GetFile("icon-management.png");
                    page.Elements.Add(new Image(ImageData.GetImage(management_details_image), 0f, currentYOffset-2, 0.3f));
                    currentYOffset += 5;
                    page.Elements.Add(new Label("Management Details", 17f, currentYOffset, 135f, 12f, Fonts.MontserratBold, 10f, TextAlign.Center, RgbColor.Black));
                    currentYOffset += 5;
                    page.Elements.Add(new Line(150f, currentYOffset, _report.PageMaxWidth, currentYOffset, 1, RgbColor.Black));
                    currentYOffset += 30;
                    top = currentYOffset;
                }
                
                maxHeight = _report.PageMaxHeight - top;

                float firstRequiredHeight = 0.0f;
                float secondRequiredHeight = 0.0f;

                var firstIndicator = standardIndicators.Skip(skip - 1).Take(1).SingleOrDefault();

                if (firstIndicator != null)
                {
                    firstTable = GetIndicatorTable(firstIndicator, x, top, maxWidth, maxHeight, parentOutlinePositions);
                    page.Elements.Add(firstTable);
                    firstRequiredHeight = firstTable.GetRequiredHeight();
                }

                var secondIndicator = standardIndicators.Skip(skip).Take(1).SingleOrDefault();

                if (secondIndicator != null)
                {
                    secondTable = GetIndicatorTable(secondIndicator, x + maxWidth + 30f, top, maxWidth, maxHeight, parentOutlinePositions);
                    page.Elements.Add(secondTable);
                    secondRequiredHeight = secondTable.GetRequiredHeight();
                }

                top += firstRequiredHeight > secondRequiredHeight ? firstRequiredHeight : secondRequiredHeight;

                firstRequiredHeight = 0;
                secondRequiredHeight = 0;

                if (firstIndicator != null && firstTable != null)
                {
                    var overflowTable = firstTable.GetOverflowRows();

                    if (overflowTable != null)
                    {
                        isNewPage = true;

                        page = new PdfReportPage_Core(_report, _dataSource, 3);
                        _report.Pages.Add(page);
                        OutlinePageCount++;

                        float currentYOffset = page.Top + 13f;
                        var management_details_image = ReportHelper.GetFile("icon-management.png");
                        page.Elements.Add(new Image(ImageData.GetImage(management_details_image), 0f, currentYOffset - 2, 0.3f));
                        currentYOffset += 5;
                        page.Elements.Add(new Label("Management Details", 17f, currentYOffset, 135f, 12f, Fonts.MontserratBold, 10f, TextAlign.Center, RgbColor.Black));
                        currentYOffset += 5;
                        page.Elements.Add(new Line(150f, currentYOffset, _report.PageMaxWidth, currentYOffset, 1, RgbColor.Black));
                        currentYOffset += 30;
                        top = currentYOffset;

                        maxHeight = _report.PageMaxHeight - top;

                        firstRequiredHeight = overflowTable.GetRequiredHeight();

                        overflowTable.Y = top;
                        overflowTable.Height = firstRequiredHeight;

                        page.Elements.Add(overflowTable);
                    }
                }

                if (secondIndicator != null && secondTable != null)
                {
                    var overflowTable = secondTable.GetOverflowRows();

                    if (overflowTable != null)
                    {
                        if (!isNewPage)
                        {
                            page = new PdfReportPage_Core(_report, _dataSource, 3);
                            _report.Pages.Add(page);
                            OutlinePageCount++;

                            float currentYOffset = page.Top + 13f;
                            var management_details_image = ReportHelper.GetFile("icon-management.png");
                            page.Elements.Add(new Image(ImageData.GetImage(management_details_image), 0f, currentYOffset - 2, 0.3f));
                            currentYOffset += 5;
                            page.Elements.Add(new Label("Management Details", 17f, currentYOffset, 135f, 12f, Fonts.MontserratBold, 10f, TextAlign.Center, RgbColor.Black));
                            currentYOffset += 5;
                            page.Elements.Add(new Line(150f, currentYOffset, _report.PageMaxWidth, currentYOffset, 1, RgbColor.Black));
                            currentYOffset += 30;
                            top = currentYOffset;

                            maxHeight = _report.PageMaxHeight - top;
                        }

                        secondRequiredHeight = overflowTable.GetRequiredHeight();

                        overflowTable.Y = top;
                        overflowTable.Height = secondRequiredHeight;

                        page.Elements.Add(overflowTable);
                    }
                }


                top += firstRequiredHeight > secondRequiredHeight ? firstRequiredHeight : secondRequiredHeight;

                top += 10f;

                page.Elements.Add(new Line(x, top, _report.PageMaxWidth, top, 1, Colors.LineColor, LineStyle.Dots));

                top += 20f;

                isNewPage = false;
            }

        }

        private Table GetIndicatorTable(CoreRiskRatingIndicator indicator, float x, float y, float maxWidth, float maxHeight, OutlinePosition parentOutlinePositions)
        {
            // 1.  Indicator code and name

            var indicatorName = indicator.Name == null ? "Indicator name placeholder" : indicator.Name;
            indicatorName = $"{indicator.Code} - {indicatorName}";

            Table table = GetDefaultTable(x, y, maxWidth, maxHeight);

            table.CellDefault.Border.Bottom.LineStyle = LineStyle.None;
            table.CellDefault.Border.Bottom.Width = 0.5f;
            table.CellDefault.Border.Color = RgbColor.Black;
            table.CellDefault.VAlign = VAlign.Center;

            table.Columns.Add(maxWidth*0.33f);
            table.Columns.Add(maxWidth*0.33f);
            table.Columns.Add(maxWidth*0.34f);

            var row = table.Rows.Add(15);
            row.Cells.Add(new TextArea(indicatorName, 0.0f, 0.0f, maxWidth, 12*2.5f,
                Fonts.RobotoBold, 12, TextAlign.Left, RgbColor.Black), 3);

            parentOutlinePositions.ChildOutlinePositions.Add(new OutlinePosition { Name = indicatorName, PageNumber = OutlinePageCount, VerticalPosition = y });

            row = table.Rows.Add(10);
            row.Cells.Add(new Line(0, 5f, maxWidth, 5f, 0.5f, RgbColor.Silver, LineStyle.Dots), 3);

            // 2. Raw Score, Weight, Weighted Score

            row = table.Rows.Add(15);
            row.Cells.Add(new Label(indicator.RawScore.Value.ToString(" #0              "), 0.0f, 0.0f, maxWidth, 11,
                Fonts.RobotoBold, 9, TextAlign.Left, RgbColor.Black));
            row.Cells.Add(new Label(indicator.FinalWeight.Value.ToString("#0.0%            "), 0.0f, 0.0f, maxWidth, 11,
                Fonts.RobotoBold, 9, TextAlign.Left, RgbColor.Black));
            row.Cells.Add(new Label(indicator.WeightedScore.Value.ToString("#0.0"), 0.0f, 0.0f, maxWidth, 11,
                Fonts.RobotoBold, 9, TextAlign.Left, RgbColor.Black));

            row = table.Rows.Add(10);
            row.Cells.Add(new Label("Raw Score", 0.0f, 0.0f, maxWidth, 9,
                Fonts.RobotoBold, 7, TextAlign.Left, RgbColor.Black));
            row.Cells.Add(new Label("Weight", 0.0f, 0.0f, maxWidth, 9,
                Fonts.RobotoBold, 7, TextAlign.Left, RgbColor.Black));
            row.Cells.Add(new Label("Weighted Score", 0.0f, 0.0f, maxWidth, 9,
                Fonts.RobotoBold, 7, TextAlign.Left, RgbColor.Black));

            // 3. Answer Category

            if (!string.IsNullOrEmpty(indicator.AnswerCategoryText))
            {
                row = table.Rows.Add(10f);
                row.Cells.Add(new Line(0, 5f, maxWidth, 5f, 0.5f, RgbColor.Silver, LineStyle.Dots), 3);

                var answerCategoryTextArea = new FormattedTextArea($"<b>{indicator.AnswerCategoryText}</b>", 0f, 0f, maxWidth, 100f, Fonts.RobotoFontFamily, 10f, false);
                var answerCategoryTextHeight = (int)answerCategoryTextArea.GetRequiredHeight() + 5f;

                row = table.Rows.Add(answerCategoryTextHeight);
                row.Cells.Add(new FormattedTextArea($"<b>{indicator.AnswerCategoryText}</b>", 0f, 0f, maxWidth, answerCategoryTextHeight, Fonts.RobotoFontFamily, 10f, false));
            }

            // 4. Analyst Commentary

            if (!string.IsNullOrEmpty(indicator.Comment.Value))
            {
                row = table.Rows.Add(10f);
                row.Cells.Add(new Line(0, 5f, maxWidth, 5f, 0.5f, RgbColor.Silver, LineStyle.Dots), 3);

                var commentTextArea = new FormattedTextArea($"<p>{indicator.Comment.Value}</p>", 0f, 0f, maxWidth, 100f, Fonts.RobotoFontFamily, 7f, false);
                var commentTextHeight = (int)commentTextArea.GetRequiredHeight() + 5f;

                row = table.Rows.Add(commentTextHeight);
                row.Cells.Add(new FormattedTextArea($"<p>{indicator.Comment.Value}</p>", 0f, 0f, maxWidth, commentTextHeight, Fonts.RobotoFontFamily, 7f, false));
            }

            // 5. Tick boxes

            var checkbox_on_image = ReportHelper.GetFile("indicator_checkbox_on.png");
            var checkbox_off_image = ReportHelper.GetFile("indicator_checkbox_off.png");

            if (indicator.CheckBoxes.Any())
            {
                row = table.Rows.Add(10f);
                row.Cells.Add(new Line(0, 5f, maxWidth, 5f, 0.5f, RgbColor.Silver, LineStyle.Dots), 3);

                row = table.Rows.Add(15);
                row.Cells.Add(new Label("Criteria", 0.0f, 0.0f, maxWidth, 9,
                    Fonts.RobotoBold, 7, TextAlign.Left, RgbColor.Black));

                foreach (var checkBox in indicator.CheckBoxes)
                {
                    
                    var checkBoxTextArea = new FormattedTextArea($"<p>{checkBox.Text}</p>", 15f, 0f, maxWidth - 15f, 100f, Fonts.RobotoFontFamily, 7f, false);
                        var checkBoxTextHeight = (int)checkBoxTextArea.GetRequiredHeight() + 5f;

                    var group = new Group();

                    group.Add(checkBox.IsChecked.Value 
                        ? new Image(ImageData.GetImage(checkbox_on_image), 0.0f, 0.0f, 0.11f) { Align = Align.Left, VAlign = VAlign.Top } 
                        : new Image(ImageData.GetImage(checkbox_off_image), 0.0f, 0.0f, 0.11f) { Align = Align.Left, VAlign = VAlign.Top });

                    group.Add(new FormattedTextArea($"<p>{checkBox.Text}</p>", 15f, 0f, maxWidth - 15f, checkBoxTextHeight, Fonts.RobotoFontFamily, 7f, false));


                    row = table.Rows.Add(checkBoxTextHeight);
                    row.Cells.Add(group);
                }
            }

            // 6. Sources

            if (indicator.Sources.Any())
            {
                row = table.Rows.Add(10f);
                row.Cells.Add(new Line(0, 5f, maxWidth, 5f, 0.5f, RgbColor.Silver, LineStyle.Dots), 3);

                row = table.Rows.Add(15);
                row.Cells.Add(new Label("Sources", 0.0f, 0.0f, maxWidth, 9,
                    Fonts.RobotoBold, 7, TextAlign.Left, RgbColor.Black));

                foreach (var source in indicator.Sources.OrderBy(s => s))
                {
                    var sourceTextArea = new FormattedTextArea($"<p>{source}</p>", 0f, 0f, maxWidth, 100f, Fonts.RobotoFontFamily, 7f, false);
                    var sourceTextHeight = (int)sourceTextArea.GetRequiredHeight() + 5f;

                    row = table.Rows.Add(sourceTextHeight);
                    row.Cells.Add(new FormattedTextArea($"<p>{source}</p>", 0f, 0f, maxWidth, sourceTextHeight, Fonts.RobotoFontFamily, 7f, false));
                }
            }

            return table;
        }

        #endregion

        #region Events Section
        private void AddMaterialIssues_EventsPage(List<CoreRiskRatingIndicator> indicators, float x, float y, float maxWidth, PdfReportPage page)
        {
            CurrentPage = page;
            Event_LeftYOffset = Event_CurrentYOffset = y + (float)VerticalSpacing.Small;

            var indicatorsCode = indicators.Where(i => i.IndicatorType == IndicatorType.EventIndicator).Select(i => new { i.Code, i.SortKey, i.AnswerCategory });

            if (_dataSource.Events == null)
                return;

            var joinResult = _dataSource.Events.Join(indicatorsCode, i => i.CanvasCode, mei => mei.Code, (i, mei) =>
            {
                i.EventCategory = mei.AnswerCategory.Value;
                return new { Indicator = i, MEI = mei };
            });


            if (joinResult == null || !joinResult.Any())
            {
                return;
            }

            var eventIndicators = joinResult.OrderByDescending(i => i.Indicator.EventCategory)
                                    //.ThenBy(i=>i.MEI.SortKey.Value)
                                    .ThenBy(i => i.Indicator.Name)
                                    .Select(i => i.Indicator)
                                    .Where(i => i.EventCategory > 0)
                                    .ToList();


            if (page != null && eventIndicators.Any())
            {
                CurrentPage = page;
                Event_CurrentYOffset = y + (float)VerticalSpacing.Small;
                Event_CurrentXOffset = 0;
                var eventIndicator = eventIndicators.First();
                var associatedIncidents = _dataSource.Incident.Where(i => i.EventIndicatorId == eventIndicator.Id).OrderByDescending(i => i.IncidentDate);
                    Event_LeftYOffset = AddEventsFirstPage(eventIndicator, associatedIncidents, Event_CurrentXOffset, Event_CurrentYOffset);
                Event_CurrentXOffset = XRightColumn;
                foreach (var incidentGroup in associatedIncidents.GroupBy(i => i.IncidentId))
                {
                    AddIncindetGroup(incidentGroup, Event_CurrentXOffset, Event_CurrentYOffset);
                }
                Event_CurrentYOffset = Math.Max(Event_LeftYOffset, Event_CurrentYOffset);
            }
            else
            {
                foreach (var eventIndicator in eventIndicators)
                {
                    var associatedIncidents = _dataSource.Incident.Where(i => i.EventIndicatorId == eventIndicator.Id).OrderByDescending(i => i.IncidentDate);

                    if (eventIndicator.EventCategory >= 3 || CheckNewPageOrNewSection(Event_CurrentYOffset) || associatedIncidents.Any())
                    {
                        AddNewPage();
                        
                    }
                    else
                    { AddNewEventSection(); }

                    Event_LeftYOffset = AddEventsFirstPage(eventIndicator, associatedIncidents, Event_CurrentXOffset, Event_CurrentYOffset);

                    Event_CurrentXOffset = XRightColumn;
                    foreach (var incidentGroup in associatedIncidents.GroupBy(i => i.IncidentId))
                    {
                        AddIncindetGroup(incidentGroup, Event_CurrentXOffset, Event_CurrentYOffset);
                    }
                    Event_CurrentYOffset = Math.Max(Event_LeftYOffset, Event_CurrentYOffset);
                }
            }
        }

        private float AddEventsFirstPage(EventIndicator eventIndicator, IEnumerable<Incident> incidents, float x, float y)
        {
            var eventSectionHeader = AddEventHeader(eventIndicator, x, y);
            var currentXOffset = x;
            var currentYOffset = eventSectionHeader.Item1;
            if (CheckNewPageOrNewSection(eventSectionHeader.Item1))
            {
                AddNewPage();
                currentXOffset = Event_CurrentXOffset;
                currentYOffset = Event_CurrentYOffset;
                eventSectionHeader = AddEventHeader(eventIndicator, currentXOffset, currentYOffset);
                currentYOffset = eventSectionHeader.Item1;
            }
            CurrentPage.Elements.Add(eventSectionHeader.Item2);

            CurrentPage.Elements.Add(new Line(0, currentYOffset, _report.PageMaxWidth, currentYOffset, 1, Colors.SectionColor));
            currentYOffset += (float)VerticalSpacing.Small;

            return AddIncidentsMap(incidents.ToList(), x, currentYOffset);

        }

        private Tuple<float,Group> AddEventHeader(EventIndicator issue, float x, float currentYOffset)
        {
            var group = new Group();

            var management_details_image = ReportHelper.GetFile("icon-management.png");
            currentYOffset += 5f;
            CurrentPage.Elements.Add(new Image(ImageData.GetImage(management_details_image), 0f, currentYOffset-2, 0.3f));
            currentYOffset += 5;
            CurrentPage.Elements.Add(new Label("Management Details", 17f, currentYOffset, 135f, 12f, Fonts.MontserratBold, 10f, TextAlign.Center, RgbColor.Black));
            currentYOffset += 5;
            CurrentPage.Elements.Add(new Line(150f, currentYOffset, _report.PageMaxWidth, currentYOffset, 1, RgbColor.Black));
            currentYOffset += 30;

            group.Add(new Label("EVENT DETAILS", x, currentYOffset, ColumnWidth, (float)TextSizes.SubSectionTitle, Fonts.MontserratRegular, (float)TextSizes.SubSectionTitle, TextAlign.Left, RgbColor.Black));

            currentYOffset += 20;
            group.Add(new Label(issue.Name + " Event", x, currentYOffset, ColumnWidth, (float)TextSizes.RegularTextSubtitle, Fonts.RobotoBold, (float)TextSizes.SectionTitle, TextAlign.Left, RgbColor.Black));

            currentYOffset += (float)TextSizes.SectionTitle + (float)VerticalSpacing.Small;

            var outlookItems = AddOutlook(issue, x, currentYOffset);

            group.Add(outlookItems.Item2);

            var analystItems = AddEventsAnalystCommentary(issue, XRightColumn, currentYOffset);

            group.Add(analystItems.Item2);

            currentYOffset = Math.Max(outlookItems.Item1, analystItems.Item1) + (float)VerticalSpacing.Large;

            return new Tuple<float,Group> (currentYOffset,group);
        }

        private Tuple<float,Group> AddOutlook(EventIndicator issue, float x, float currentYOffset)
        {
            var elements = new Group();

            var image = new Image(ImageData.GetImage(ReportHelper.GetEventImage(issue.EventCategory)), x, currentYOffset, 0.33f);
            elements.Add(image);
            var currentX = x + image.Width;
            var currentY = currentYOffset + (image.Height - (float)TextSizes.SubSectionTitle) / 2;

            elements.Add(new Label(issue.EventCategoryText, currentX, currentY, ColumnWidth / 2, (float)TextSizes.SubSectionTitle, Fonts.RobotoRegular, (float)TextSizes.SubSectionTitle, TextAlign.Left, RgbColor.Black));

            currentX = ColumnWidth / 2;

            if (issue.EventCategory >= 3)
            {
                var outlookLabelImageWidth = 18f;
                if (issue.OutlookLabel != null)
                {
                    var arroImage = new Image(ImageData.GetImage(ReportHelper.GetOutlookImage(issue.OutlookLabel ?? string.Empty)), currentX, currentYOffset + 7, 0.75f);
                    outlookLabelImageWidth = arroImage.Width;
                    elements.Add(arroImage);
                }

                currentYOffset += image.Height;
                elements.Add(new Label("Outlook", currentX, currentYOffset, ColumnWidth, (float)TextSizes.SubSectionTitle, Fonts.RobotoRegular, (float)TextSizes.SubSectionTitle, TextAlign.Left, RgbColor.Black));

                currentX += outlookLabelImageWidth;

                elements.Add(new Label(issue.OutlookLabel ?? string.Empty, currentX, currentY, ColumnWidth / 2, (float)TextSizes.SubSectionTitle, Fonts.RobotoRegular, (float)TextSizes.SubSectionTitle, TextAlign.Left, RgbColor.Black));
            }
            else
            {
                currentYOffset = currentY = currentYOffset + image.Height;
            }

            elements.Add(new Label("Event Category", x, currentYOffset, ColumnWidth, (float)TextSizes.SubSectionTitle, Fonts.RobotoRegular, (float)TextSizes.SubSectionTitle, TextAlign.Left, RgbColor.Black));

            currentYOffset += (float)TextSizes.SubSectionTitle + (float)VerticalSpacing.Small;

            if (!string.IsNullOrEmpty(issue.OutlookText))
            {
                elements.Add(SectionTile("Outlook", x, currentYOffset));

                currentYOffset += (float)TextSizes.SubSectionTitle + (float)VerticalSpacing.Small;

                FormattedTextArea textArea = new FormattedTextArea(issue.OutlookText, x, currentYOffset, ColumnWidth, 500, Fonts.RobotoFontFamily, (float)TextSizes.RegularTextSubtitle, false);
                elements.Add(textArea);

                currentYOffset += textArea.GetRequiredHeight() + (float)VerticalSpacing.Small;

                issue.OutlookComments?.ForEach(comment =>
                {
                    textArea = new FormattedTextArea(comment, x, currentYOffset, ColumnWidth, 500, Fonts.RobotoFontFamily, (float)TextSizes.RegularText, false);
                    elements.Add(textArea);
                    currentYOffset += textArea.GetRequiredHeight() + (float)VerticalSpacing.Small;
                });
            }

            return new Tuple<float,Group> (currentYOffset,elements);
        }

        private Label SectionTile(string title, float x, float y) => new Label(
                    title,
            x,
            y,
            _report.PageMaxWidth,
            (float)TextSizes.SubSectionTitle,
            Fonts.RobotoBold,
            (float)TextSizes.SubSectionTitle,
            TextAlign.Left,
            RgbColor.Black);

        private Tuple<float,Group> AddEventsAnalystCommentary(EventIndicator issue, float x, float y)
        {
            var elements = new Group();
            float currentYOffset = y;
            if (issue == null || string.IsNullOrEmpty(issue.ControversySummary))
                return new Tuple<float,Group>(currentYOffset,elements);

            elements.Add(SectionTile("Assessment", x, currentYOffset));

            currentYOffset += (float)TextSizes.SubSectionTitle + (float)VerticalSpacing.Small;

            FormattedTextArea textArea = new FormattedTextArea(issue.ControversySummary, x, currentYOffset, ColumnWidth, 500, Fonts.RobotoFontFamily, 7, false);
            elements.Add(textArea);

            currentYOffset += textArea.GetRequiredHeight() + (float)VerticalSpacing.Small;

            textArea = new FormattedTextArea(issue.EventJustification ?? string.Empty, x, currentYOffset, ColumnWidth, 500, Fonts.RobotoFontFamily, 7, false);
            elements.Add(textArea);

            currentYOffset += textArea.GetRequiredHeight();

            return new Tuple<float, Group>(currentYOffset, elements);
        }
        private void AddNewEventSection()
        {
            Event_CurrentYOffset += (float)VerticalSpacing.Small;
            Event_CurrentXOffset = 0;

        }

        private float AddIncidentsMap(List<Incident> incidents, float x, float currentYOffset)
        {
            if (!incidents.Any())
            {
                Event_CurrentYOffset = currentYOffset;
                return currentYOffset;
            }
            CurrentPage.Elements.Add(SectionTile("Incident History", x, currentYOffset));

            currentYOffset += (float)TextSizes.SubSectionTitle + (float)VerticalSpacing.Small;

            Event_CurrentYOffset = currentYOffset;

            var map = new Image(ImageData.GetImage(IncidentsMap.GetMapImageOptimized(incidents.Select(l => l.Location).ToList(), (int)ColumnWidth, (int)ColumnWidth, MapSize.Big)), x, currentYOffset - ColumnWidth / 5, 0.98f);
            CurrentPage.AddElement(map);

            currentYOffset += ColumnWidth / 2 + (float)VerticalSpacing.Small;

            HashSet<string> addresses = new HashSet<string>();
            HashSet<string> tags = new HashSet<string>();
            incidents.ForEach(i =>
            {
                if (!addresses.Contains(i.Location.Address)) { addresses.Add(i.Location.Address); }
                if (!tags.Contains(i.MainTag)) { tags.Add(i.MainTag); }
            });

            if (addresses.Any())
            {
                var textArea = new FormattedTextArea("<b>Locations:</b> " + addresses.Aggregate((a, b) => a + ", " + b), x, currentYOffset, ColumnWidth, 500, Fonts.RobotoFontFamily, (float)TextSizes.RegularText, false);
                CurrentPage.Elements.Add(textArea);
                currentYOffset += textArea.GetRequiredHeight() + (float)VerticalSpacing.Small;
            }

            if (tags.Any())
            {
                var textArea = new FormattedTextArea("<b>Tags:</b> " + tags.Aggregate((a, b) => a + ", " + b), x, currentYOffset, ColumnWidth, 500, Fonts.RobotoFontFamily, (float)TextSizes.RegularText, false);
                CurrentPage.Elements.Add(textArea);
                currentYOffset += textArea.GetRequiredHeight() + (float)VerticalSpacing.Small;
            }
            return currentYOffset;
        }

        private void AddIncindetGroup(IGrouping<string, Incident> incidentGroup, float x, float y)
        {
            float currentYOffset = y;
            float currentXOffset = x;
            var incidents = incidentGroup.OrderByDescending(i => i.IncidentDate).ToArray();
            Tuple<float, Group> item;
            Incident mainIncident = incidents.FirstOrDefault(i => i.IsMain);

            if (mainIncident != null)
            {
                item = AddIncident(currentXOffset, currentYOffset, mainIncident);
                var incidentHeight = Math.Abs(currentYOffset - item.Item1);

                if (CheckNewPageOrNewSection(item.Item1 + incidentHeight))
                {
                    currentXOffset = Event_CurrentXOffset;
                    currentYOffset = Event_CurrentYOffset;
                    item = AddIncident(currentXOffset, currentYOffset, mainIncident);
                    currentYOffset = Event_CurrentYOffset = item.Item1;
                    CurrentPage.Elements.Add(item.Item2);
                }
                else
                {
                    currentYOffset = Event_CurrentYOffset = item.Item1;
                    currentXOffset = Event_CurrentXOffset;
                    CurrentPage.Elements.Add(item.Item2);
                }
            }

            foreach (var incident in incidents.Where(i => !i.IsMain))
            {
                if (incident != null)
                {
                    item = AddIncident(currentXOffset + 20, currentYOffset, incident, $"Update: {incident.Name}");

                    if (CheckNewPageOrNewSection(item.Item1))
                    {
                        currentXOffset = Event_CurrentXOffset;
                        currentYOffset = Event_CurrentYOffset;
                        item = AddIncident(currentXOffset, currentYOffset, mainIncident);
                        currentYOffset = item.Item1;
                        CurrentPage.Elements.Add(item.Item2);
                        item = AddIncident(currentXOffset + 20, currentYOffset, incident, $"Update: {incident.Name}");
                    }

                    currentYOffset = Event_CurrentYOffset = item.Item1;
                    currentXOffset = Event_CurrentXOffset;
                    CurrentPage.Elements.Add(item.Item2);
                }
            }

            Event_CurrentYOffset += (float)VerticalSpacing.Small;
        }

        private Tuple<float, Group> AddIncident(float x, float currentYOffset, Incident incident, string IncidentName = null)
        {
            var group = new Group();
            group.Add(new Label(
                IncidentName ?? incident.Name,
                x,
                currentYOffset,
                ColumnWidth,
                (float)TextSizes.RegularText,
                Fonts.RobotoBold,
                (float)TextSizes.RegularText,
                TextAlign.Left,
                RgbColor.Black));
            currentYOffset += (float)TextSizes.RegularText + 2;
            var labelText = $"{ incident.Source } - { incident.IncidentDate.ToString("dd MMMM yyyy") } ";
            var labelColor = RgbColor.Black;

            if (!string.IsNullOrWhiteSpace(incident.ExternalUrl))
            {
                labelColor = new RgbColor(255, 165, 0);
                var action = new UrlAction(incident.ExternalUrl);
                var incidentLink = new Link(x, currentYOffset, Fonts.RobotoBold.GetTextWidth(labelText, 7), (float)TextSizes.RegularText, action);
                group.Add(incidentLink);
            }

            var label = new Label(
                labelText,
                x,
                currentYOffset,
                ColumnWidth,
                (float)TextSizes.RegularText,
                Fonts.RobotoRegular,
                (float)TextSizes.RegularText,
                TextAlign.Left,
                labelColor);

            group.Add(label);

            currentYOffset += (float)TextSizes.RegularText + (float)VerticalSpacing.Small;
            return new Tuple<float, Group>(currentYOffset, group);
        }

        private bool CheckNewPageOrNewSection(float offset)
        {
            Event_CurrentYOffset = offset;
            if (CurrentPage == null)
            {

                return true;
            }
            if (offset >= CurrentPage.Dimensions.Height - CurrentPage.Top)
            {
                if (Event_CurrentXOffset >= XRightColumn)
                {
                    AddNewPage();
                    return true;
                }
                Event_CurrentXOffset = XRightColumn; Event_CurrentYOffset = CurrentPage.Top + (float)VerticalSpacing.Small;
                return true;
            }
            return false;
        }

        private void AddNewPage()
        {
            CurrentPage = new PdfReportPage_Core(_report, _dataSource, 3);
            _report.Pages.Add(CurrentPage);
            OutlinePageCount++;
            Event_CurrentYOffset = Event_LeftYOffset =  CurrentPage.Top + (float)VerticalSpacing.Small;
            Event_CurrentXOffset = 0;

            
        }

        #endregion
    }
}
